"""
Radar Packet Protocol

实现雷达数据包的封装和解析
"""

import struct
from typing import Union, Optional
from .checksum import Checksum
from .parser import RadarTarget, RadarStatus, DataParser
from ..exceptions import RadarProtocolError, RadarChecksumError


class RadarPacket:
    """雷达数据包协议类"""

    # 帧头和帧尾定义
    RJ45_HEADER = b'\xAA\x55'
    RJ45_TAIL = b'\x55\xAA'
    RS232_START_MARKER = b'\xAA'
    RS232_END_MARKER = b'\x55'

    # 命令代码
    CMD_START_SCAN = 0x01
    CMD_STOP_SCAN = 0x02
    CMD_GET_STATUS = 0x03
    CMD_CONFIG = 0x04
    CMD_GET_TARGETS = 0x05
    CMD_RESET = 0x06

    # 状态码
    STATUS_SUCCESS = 0x00
    STATUS_INVALID_CMD = 0x01
    STATUS_INVALID_PARAM = 0x02
    STATUS_DEVICE_BUSY = 0x03
    STATUS_HARDWARE_ERROR = 0x04
    STATUS_TIMEOUT = 0x05

    @staticmethod
    def create_rj45_packet(command: int, data: bytes = b'') -> bytes:
        """
        创建RJ45数据包

        Args:
            command: 命令代码
            data: 数据部分

        Returns:
            完整的RJ45数据包
        """
        # 构建数据包
        packet = bytearray()
        packet.extend(RadarPacket.RJ45_HEADER)  # 帧头 (2B)
        packet.extend(struct.pack('>H', len(data)))  # 长度 (2B)
        packet.extend(struct.pack('>B', command))  # 命令 (1B)
        packet.extend(data)  # 数据 (N B)

        # 计算CRC16校验
        checksum = Checksum.crc16(packet[2:])  # 从长度字段开始计算
        packet.extend(checksum)  # 校验 (2B)
        packet.extend(RadarPacket.RJ45_TAIL)  # 帧尾 (2B)

        return bytes(packet)

    @staticmethod
    def create_rs232_packet(command: int, data: bytes = b'', address: int = 0x01) -> bytes:
        """
        创建RS232数据帧

        Args:
            command: 命令代码
            data: 数据部分
            address: 设备地址

        Returns:
            完整的RS232数据帧
        """
        # 构建数据帧
        frame = bytearray()
        frame.extend(RadarPacket.RS232_START_MARKER)  # 起始符 (1B)
        frame.extend(struct.pack('>B', address))  # 地址 (1B)
        frame.extend(struct.pack('>B', command))  # 命令 (1B)
        frame.extend(struct.pack('>H', len(data)))  # 数据长度 (2B)
        frame.extend(data)  # 数据 (N B)

        # 计算XOR校验
        checksum = Checksum.xor_checksum(frame[1:])  # 从地址字段开始计算
        frame.extend(checksum)  # 校验 (1B)
        frame.extend(RadarPacket.RS232_END_MARKER)  # 结束符 (1B)

        return bytes(frame)

    @staticmethod
    def parse_rj45_packet(data: bytes) -> tuple:
        """
        解析RJ45数据包

        Args:
            data: 接收到的数据包

        Returns:
            (命令代码, 数据部分, 状态码)
        """
        try:
            # 检查最小长度
            if len(data) < 9:
                raise RadarProtocolError("数据包长度不足")

            # 检查帧头和帧尾
            if data[:2] != RadarPacket.RJ45_HEADER:
                raise RadarProtocolError("帧头错误")
            if data[-2:] != RadarPacket.RJ45_TAIL:
                raise RadarProtocolError("帧尾错误")

            # 解析各字段
            length = struct.unpack('>H', data[2:4])[0]
            command = data[4]
            packet_data = data[5:5+length]
            checksum = data[5+length:7+length]

            # 验证校验
            calculated_checksum = Checksum.crc16(data[2:5+length])
            if not Checksum.verify_crc16(data[2:5+length], checksum):
                raise RadarChecksumError("CRC16校验失败")

            return command, packet_data, RadarPacket.STATUS_SUCCESS

        except (IndexError, struct.error) as e:
            raise RadarProtocolError(f"解析RJ45数据包失败: {e}")

    @staticmethod
    def parse_rs232_packet(data: bytes) -> tuple:
        """
        解析RS232数据帧

        Args:
            data: 接收到的数据帧

        Returns:
            (地址, 命令代码, 数据部分, 状态码)
        """
        try:
            # 检查最小长度
            if len(data) < 8:
                raise RadarProtocolError("数据帧长度不足")

            # 检查起始符和结束符
            if data[0:1] != RadarPacket.RS232_START_MARKER:
                raise RadarProtocolError("起始符错误")
            if data[-1:] != RadarPacket.RS232_END_MARKER:
                raise RadarProtocolError("结束符错误")

            # 解析各字段
            address = data[1]
            command = data[2]
            length = struct.unpack('>H', data[3:5])[0]
            frame_data = data[5:5+length]
            checksum = data[5+length]

            # 验证校验
            calculated_checksum = Checksum.xor_checksum(data[1:5+length])
            if not Checksum.verify_xor(data[1:5+length], checksum):
                raise RadarChecksumError("XOR校验失败")

            return address, command, frame_data, RadarPacket.STATUS_SUCCESS

        except (IndexError, struct.error) as e:
            raise RadarProtocolError(f"解析RS232数据帧失败: {e}")

    @staticmethod
    def create_command_packet(command: int, params: dict = None, interface_type: str = 'rj45') -> bytes:
        """
        创建命令数据包

        Args:
            command: 命令代码
            params: 命令参数
            interface_type: 接口类型 ('rj45' 或 'rs232')

        Returns:
            命令数据包
        """
        # 构建参数数据
        data = bytearray()
        if params:
            for key, value in params.items():
                if isinstance(value, int):
                    data.extend(struct.pack('>I', value))
                elif isinstance(value, float):
                    data.extend(struct.pack('>f', value))
                elif isinstance(value, str):
                    data.extend(value.encode('utf-8'))
                elif isinstance(value, bytes):
                    data.extend(value)

        if interface_type.lower() == 'rj45':
            return RadarPacket.create_rj45_packet(command, bytes(data))
        else:
            return RadarPacket.create_rs232_packet(command, bytes(data))

    @staticmethod
    def parse_response_packet(data: bytes, interface_type: str = 'rj45') -> tuple:
        """
        解析响应数据包

        Args:
            data: 响应数据
            interface_type: 接口类型 ('rj45' 或 'rs232')

        Returns:
            (状态码, 数据部分)
        """
        if interface_type.lower() == 'rj45':
            command, data, status = RadarPacket.parse_rj45_packet(data)
            return status, data
        else:
            address, command, data, status = RadarPacket.parse_rs232_packet(data)
            return status, data

    @staticmethod
    def parse_targets_data(data: bytes) -> list:
        """
        解析目标数据

        Args:
            data: 目标数据

        Returns:
            雷达目标列表
        """
        try:
            return DataParser.parse_targets(data)
        except Exception as e:
            raise RadarProtocolError(f"解析目标数据失败: {e}")

    @staticmethod
    def parse_status_data(data: bytes) -> RadarStatus:
        """
        解析状态数据

        Args:
            data: 状态数据

        Returns:
            雷达状态对象
        """
        try:
            return RadarStatus.from_bytes(data)
        except Exception as e:
            raise RadarProtocolError(f"解析状态数据失败: {e}")

    @staticmethod
    def get_command_name(command: int) -> str:
        """
        获取命令名称

        Args:
            command: 命令代码

        Returns:
            命令名称
        """
        command_map = {
            RadarPacket.CMD_START_SCAN: "启动雷达扫描",
            RadarPacket.CMD_STOP_SCAN: "停止雷达扫描",
            RadarPacket.CMD_GET_STATUS: "获取雷达状态",
            RadarPacket.CMD_CONFIG: "配置雷达参数",
            RadarPacket.CMD_GET_TARGETS: "获取目标数据",
            RadarPacket.CMD_RESET: "重置雷达系统"
        }
        return command_map.get(command, f"未知命令(0x{command:02X})")

    @staticmethod
    def get_status_name(status: int) -> str:
        """
        获取状态名称

        Args:
            status: 状态代码

        Returns:
            状态名称
        """
        status_map = {
            RadarPacket.STATUS_SUCCESS: "成功",
            RadarPacket.STATUS_INVALID_CMD: "命令无效",
            RadarPacket.STATUS_INVALID_PARAM: "参数错误",
            RadarPacket.STATUS_DEVICE_BUSY: "设备忙",
            RadarPacket.STATUS_HARDWARE_ERROR: "硬件错误",
            RadarPacket.STATUS_TIMEOUT: "超时错误"
        }
        return status_map.get(status, f"未知状态(0x{status:02X})")